#ifndef _D3D_D3DShader_
#define _D3D_D3DShader_

#include <windows.h>
#include <d3dx9.h>

#include "..\..\common\types.h"
#include "..\..\common\string.h"
#include "..\..\common\arraylist.hpp"
#include "..\..\common\hashtable.hpp"

#include "..\interface_types.h"
#include "..\d3d_texture.h"

extern D3DVERTEXELEMENT9 InstanceDecl[];

struct D3DMesh;
/**************************************
 *Implementation of the shader for the
 *D3D device
 **************************************/
struct D3DShader : public IResource
{	
private:
	static HRESULT CreateEffectPool();
	static HRESULT ReleaseEffectPool();
	static LPD3DXEFFECTPOOL m_pEffectPool;
	static FogData m_Fog;


	friend class CD3D9Device;

protected:
	virtual D3DVERTEXELEMENT9* GetVertexDeclarationElements();
	LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
	unsigned int m_MeshCount; 
	unsigned int m_TotalInstanceCount; 
	unsigned int m_SubmittedVertexCount; 
	unsigned int m_vbInstanceSize;
	virtual unsigned int RenderOrder();
	struct InstanceData{
		float fData[4][4]; 
	}; 

	D3DShader(CD3D9Device* const pDevice); 
	virtual ~D3DShader(); 
	virtual void ReleaseResources(); 	

	virtual HRESULT InitalizeParameters(LPD3DXEFFECT pEffect);
	virtual HRESULT UpdateParameters(LPD3DXEFFECT pEffect);
	void SetTextures(D3DRenderable * const pMesh);
	LPD3DXEFFECTPOOL GetEffectPool();

	virtual HRESULT ConstructInstanceBuffer();
	
	LPDIRECT3DVERTEXBUFFER9 m_pInstanceVB;
	LPDIRECT3DVERTEXBUFFER9 m_pMeshVB;
	D3DXHANDLE m_pProjectionHandle; 
	D3DXHANDLE m_pViewHandle; 
	D3DXHANDLE m_pTimeHandle; 
	D3DXHANDLE m_pFogHandle; 
	HashTable<InstanceData, D3DRenderable*> m_MeshHashInstances; 
	unsigned int m_lastInstanceCount; 

public:
	//TODO: make private
	LPD3DXEFFECT m_pEffect; 

	enum TextureUnit
	{
		UNIT_A = 0,
		UNIT_B = 1,
		UNIT_C = 2,
		UNIT_MASK = 3
	}; 

	virtual void AddRenderQue(D3DRenderable* pMesh, const Matrix4f& transform); 
	virtual HRESULT Create(const string& szFilename); 
	virtual HRESULT Release(); 
	virtual HRESULT	Reload(void); 

	virtual void PreExecute();	
	virtual void PostExecute();
	virtual void Execute(const int flags = RENDER_DEFAULT); 
	string GetType() const; 
	virtual void FlushRenderList(void);

	void SetFogParameters(const FogData& fog);
	FogData GetFogParameters();

	static bool funcRenderOrderSort(D3DShader* pA, D3DShader* pB);
}; 

#endif